package com.web.admin.controller;

import com.alibaba.fastjson.JSONObject;
import com.web.common.data.URL;
import com.web.component.redis.util.JedisUtil;
import com.web.component.shiro.jwt.CustomizedToken;
import com.web.component.shiro.util.JwtUtil;
import com.web.component.shiro.util.UserUtil;
import com.web.dao.model.common.Constant;
import com.web.dao.model.common.ResultVo;
import com.web.dao.model.dto.request.PassWordLoginDTO;
import com.web.dao.result.ResultVoUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录
 * @author zhang-rongyao
 * @version V 1.0
 * @Package com.fapiao.layui.controller
 * @date 2021/1/6/006 16:15
 */
@Slf4j
@Controller
public class LoginController implements ErrorController {

    /**
     * RefreshToken过期时间
     */
    @Value("${refreshTokenExpireTime}")
    private String refreshTokenExpireTime;

    private String LOGIN_TYPE="UserShiroRealm";

    @Autowired
    private UserUtil userUtil;

    @GetMapping(value = {"/login","/"})
    public String toLogin() {

        return "/login";
    }

    /**
     * 登录
     * @return main.html
     */
    @PostMapping(value = "/sys/login")
    @ResponseBody
    public ResultVo login(@Validated PassWordLoginDTO user, HttpServletResponse httpServletResponse,Model model) {
        // 根据用户名和密码创建CustomizedToken：登录token
        CustomizedToken token = new CustomizedToken(user.getUsername(), user.getPassword(), LOGIN_TYPE);
        // 获取 subject 认证主体
        Subject subject = SecurityUtils.getSubject();
        //开始认证，执行doAuthenticate()进行realm选择
        subject.login(token);
        //Shiro认证通过后会将user信息放到subject内，生成token并返回
        String account = (String) subject.getPrincipal();
        // 清除可能存在的Shiro权限信息缓存
        if (JedisUtil.exists(Constant.PREFIX_SHIRO_CACHE + account)) {
            JedisUtil.delKey(Constant.PREFIX_SHIRO_CACHE + account);
        }
        // redis设置RefreshToken，时间戳为当前时间戳，直接设置即可(不用先删后设，会覆盖已有的RefreshToken)
        String currentTimeMillis = String.valueOf(System.currentTimeMillis());
        JedisUtil.setObject(Constant.PREFIX_SHIRO_REFRESH_TOKEN + account, currentTimeMillis, Integer.parseInt(refreshTokenExpireTime));
        // 从Header中Authorization返回AccessToken，时间戳为当前时间戳
        String tokens = JwtUtil.sign(account, currentTimeMillis);
        log.info("返回加密的Token[{}]",tokens);
        httpServletResponse.setHeader("Authorization", tokens);
        httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization");
        model.addAttribute("username",user.getUsername());
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("username",user.getUsername());
        jsonObject.put("login_url",new URL("/main"));
        return ResultVoUtil.success("登录成功啦~.~",jsonObject);
    }

    /**
     * 退出登录
     */
    @GetMapping("/logout")
    public String logout() {
        SecurityUtils.getSubject().logout();
        return "redirect:/login";
    }

    /**
     * 权限不足页面
     */
    @GetMapping("/noAuth")
    public String noAuth() {
        return "/error/4xx";
    }


    @GetMapping("/main")
    public String main() {
        return "/main";
    }

    /**
     * 自定义错误页面
     */
    @Override
    public String getErrorPath() {
        return "/error";
    }

    /**
     * 处理错误页面
     */
    @RequestMapping("/error")
    public String handleError(Model model, HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        String errorMsg = "好像出错了呢！";
        if (statusCode == 404) {
            errorMsg = "页面找不到了！好像是去火星了~";
        }

        model.addAttribute("statusCode", statusCode);
        model.addAttribute("msg", errorMsg);
        return "/error/4xx";
    }
}
